<?php
/**
 * 开放平台的微信用户
 *
 * Author: Zeon
 * Date: 2017/11/28
 * Created by Panxsoft.
 */
namespace App\Models\OpenWechat;

use App\Models\Admin\StoreAdmin;
use App\Models\Concerns\ScopeFilterable;
use App\Models\Contracts\OAuthUser;
use App\Models\Customer\Customer;
use App\Models\MayPromoCoupon\MayPromoCoupon;
use App\Models\Panx\SkinDetector;
use App\Models\Panx\SkinRecordBonus;
use App\Models\Store\HmSkinRecord;
use App\Models\Store\SkinRecord;
use App\Models\Store\Store;
use App\Models\Store\WaxSkinRecord;
use App\Models\User;
use App\Services\OpenWechat\Mock;
use App\Services\OpenWechat\WechatUserRepository;
use App\Services\Utils\UrlParser;
use App\Services\Utils\Uuid;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Str;

/**
 * Class WechatUser
 *
 * @property int id - ID
 * @property int authorizer_id
 * @property int user_id
 * @property int subscribe - 订阅状态
 * @property string openid - 微信唯一ID
 * @property string nickname - 从 UTF8 nickname_unicode 转成昵称 (getter)
 * @property string nickname_unicode - unicode格式的昵称，兼容emoji
 * @property string language
 * @property string headimgurl
 * @property Carbon updated_at
 * @property string|null address
 * @property string|null city
 * @property string|null province
 * @property string|null country
 *
 * @property-read Authorizer|null authorizer
 * @property-read User|null user
 *
 * @package App\Models\Wechat
 * @mixin Builder
 */
class WechatUser extends Model implements OAuthUser
{
    use ScopeFilterable;

    const UN_SUBSCRIBE = 0;
    const SUBSCRIBED = 1;
    const LANGUAGE_ENGLISH = 'en';
    const LANGUAGE_CHINESE= 'zh-CN';
    const USER_ID_DEFAULT = 0;

    public $table = 'wechat_users';

    protected static $unguarded = true;

    protected $casts = [
        'authorizer_id' => 'int',
        'user_id'       => 'int',
        'subscribe'     => 'int',
        'phone'         => 'string',
        'longitude'     => 'float',
        'latitude'      => 'float',
    ];

    protected $guarded = [];

    /**
     * @var array - 默认不显示
     */
    protected $hidden = ['nickname_unicode'];

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function authorizer(): BelongsTo
    {
        return $this->belongsTo(Authorizer::class);
    }

    /**
     * @return string
     */
    public function decodeNickName(): ?string
    {
        return json_decode($this->nickname_unicode);
    }

    /**
     * @used-by nickname
     *
     * @return null|string
     */
    public function getNicknameAttribute(): ?string
    {
        return $this->decodeNickName();
    }
    /**
     * 保存未订阅只是通过网页授权的微信用户数据
     *
     * @param array $user_info
     * @see Mock::userGetOriginal()
     *
     * @return bool
     */
    public function updateOauthOriginUserInfo(array $user_info): bool
    {
        return $this->update([
            "openid"     => $user_info["openid"],
            "nickname"   => $user_info["nickname"],
            "sex"        => $user_info["sex"],
            "language"   => $user_info["language"],
            "city"       => $user_info["city"],
            "province"   => $user_info["province"],
            "country"    => $user_info["country"],
            "headimgurl" => $user_info["headimgurl"],

            "authorizer_id" => $user_info["authorizer_id"],
            'nickname_unicode' => json_encode($user_info['nickname']),
        ]);
    }

    /**
     * @deprecated - 保存网页授权已订阅微信用户数据
     * @see WechatUserRepository::createOrUpdateWechatUserInfo() - 请使用这个
     *
     * @param array $user_info
     * @see Mock::appUserGet()
     *
     * @return bool
     */
    public function updateOauthAppUserGetInfo(array $user_info): bool
    {
        return $this->update([
            "openid"         => $user_info["openid"],
            "nickname"       => $user_info["nickname"],
            "sex"            => $user_info["sex"],
            "language"       => $user_info["language"],
            "city"           => $user_info["city"],
            "province"       => $user_info["province"],
            "country"        => $user_info["country"],
            "headimgurl"     => $user_info["headimgurl"],
            "subscribe"      => $user_info["subscribe"],
            "subscribe_time" => $user_info["subscribe_time"],
            "subscribe_scene"=> $user_info["subscribe_scene"],
            "remark"         => $user_info["remark"],

            "authorizer_id"  => $user_info["authorizer_id"],
            'nickname_unicode' => json_encode($user_info['nickname']),
        ]);
    }

    /**
     * @param string $openid
     * @return self|Model
     */
    public static function firstOrCreateByOpenId(string $openid): ?self
    {
        return (new self)->firstOrCreate([
            'openid' => $openid
        ]);
    }

    /**
     * 返回一个mock数据
     *
     *
     * @return WechatUser
     */
    public static function mockUser(): self
    {
        // !!! 不要修改Example方法中的示例数据 !!!
        $user = new self(Mock::appUserGet());

        // 如果需要扩展请在这里修改 ...
//        $user->openid = '你要测试的OPENID';

        return $user;
    }

    /**
     * @param $openid
     * @return self|null
     */
    public static function findByOpenId(string $openid = null): ?self
    {
        return (new self)->where('openid', $openid)->first();
    }

    /**
     * @param $openid
     * @return mixed
     */
    public static function unSubscribeByOpenId(string $openid = null): bool
    {
        $user = self::findByOpenId($openid);

        if ($user) {
            return $user->unSubscribe();
        }

        return false;
    }

    /**
     * @return bool
     */
    private function unSubscribe(): bool
    {
        return $this->update([
            'subscribe' => self::UN_SUBSCRIBE,
        ]);
    }

    /**
     * @param Builder $builder
     * @param bool|null $is_subscribed
     * @return Builder
     */
    public function scopeFilterSubscribed(Builder $builder, ?bool $is_subscribed = true): Builder
    {
        return $builder->where('subscribe', $is_subscribed);
    }

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class,'user_id','id');
    }

    public function isSubscribed(): bool
    {
        return $this->subscribe === self::SUBSCRIBED;
    }

    /**
     * @used-by headimgurl
     *
     * @return null|string
     */
    public function getHeadimgurlAttribute(): ?string
    {
        $url = $this->attributes['headimgurl'] ?? null;

        return $url
            ? UrlParser::toSecure($url)
            : $url;
    }
}
